var fs = require("fs");
var path = require("path");
var crypto = require("crypto");
let JSZIP = require("jszip");
var config = require("./Config")
var param = config.inputparam; //子包配置，name version
var qudao = config.qudao;
var hoturl = config.hoturl+qudao;
var manifest = {
    packageUrl: hoturl,
    remoteManifestUrl: hoturl + "hall/" + "project.manifest",
    remoteVersionUrl: hoturl + "hall/" + "version.manifest",
    version: "1.0.4",
    assets: {},
    searchPaths: [],
    module: "hall"
};

var dest = config.dest;
var src = config.src;
var hallversion = "0.0.0";

param.forEach(element => {
    if (element.name == "hall") {
        hallversion = element.version;
    }
});

manifest.version = hallversion;
url = hoturl;
manifest.packageUrl = url + "hall/";
manifest.remoteManifestUrl = url + "project.manifest";
manifest.remoteVersionUrl = url + "version.manifest";

var copydir = function (src, dst, copyendcall) {
    let paths = fs.readdirSync(src); //同步读取当前目录
    paths.forEach(function (path) {
        var _src = src + '/' + path;
        var _dst = dst + '/' + path;
        fs.stat(_src, function (err, stats) { //stats  该对象 包含文件属性
            if (err) throw err;
            if (stats.isFile()) { //如果是个文件则拷贝 
                let readable = fs.createReadStream(_src); //创建读取流
                let writable = fs.createWriteStream(_dst); //创建写入流
                readable.pipe(writable);
            } else if (stats.isDirectory()) { //是目录则 递归 
                checkDirectory(_src, _dst, copydir, null);
                return;
            }
        });
    });
    if (copyendcall) {
        copyendcall();
    }
}

var checkDirectory = function (src, dst, callback, copyendcall) {
    fs.access(dst, fs.constants.F_OK, (err) => {
        if (err) {
            fs.mkdirSync(dst);
            callback(src, dst, copyendcall);
        } else {
            callback(src, dst, copyendcall);
        }
    });
};


function delDir(path, endcallback) {
    let files = [];
    if (fs.existsSync(path)) {
        files = fs.readdirSync(path);
        files.forEach((file, index) => {
            let curPath = path + "/" + file;
            if (fs.statSync(curPath).isDirectory()) {
                delDir(curPath, null); //递归删除文件夹
            } else {
                fs.unlinkSync(curPath); //删除文件
            }
        });
        fs.rmdirSync(path);
        if (endcallback) {
            endcallback()
        }
    }
}

//读取目录及文件
function readDirZip(obj, nowPath) {
    let files = fs.readdirSync(nowPath); //读取目录中的所有文件及文件夹（同步操作）
    files.forEach(function (fileName, index) { //遍历检测目录中的文件
        let fillPath = nowPath + "/" + fileName;
        let file = fs.statSync(fillPath); //获取一个文件的属性
        if (file.isDirectory()) { //如果是目录的话，继续查询
            let dirlist = obj.folder(fileName); //压缩对象中生成该目录
            readDirZip(dirlist, fillPath); //重新检索目录文件
        } else {
            obj.file(fileName, fs.readFileSync(fillPath)); //压缩目录添加文件
        }
    });
}

//开始压缩文件
function startZIP(inputpath, endcallback) {
    var targetDir = path.join(inputpath, "res/import");
    console.log(targetDir + "开始压缩.....")
    let zip = new JSZIP();
    readDirZip(zip, targetDir);
    zip.generateAsync({ //设置压缩格式，开始打包
        type: "nodebuffer", //nodejs用
        compression: "DEFLATE", //压缩算法
    }).then(function (content) {
        fs.writeFileSync(inputpath + "/import.zip", content, "utf-8"); //将打包的内容写入 当前目录下的 result.zip中
        delDir(targetDir, function () {
            fs.mkdirSync(inputpath + "res/import/");
            fs.renameSync(inputpath + "import.zip", inputpath + "res/import/" + "import.zip")
            endcallback();
        });
        console.log(targetDir + "压缩结束.....")
    });
}


function readDir(dir, obj) {
    var stat = fs.statSync(dir);
    if (!stat.isDirectory()) {
        return;
    }
    var subpaths = fs.readdirSync(dir),
        subpath,
        size,
        md5,
        compressed,
        relative;
    for (var i = 0; i < subpaths.length; ++i) {
        if (subpaths[i][0] === ".") {
            continue;
        }
        subpath = path.join(dir, subpaths[i]);
        stat = fs.statSync(subpath);
        if (stat.isDirectory()) {
            readDir(subpath, obj);
        } else if (stat.isFile()) {
            // Size in Bytes
            size = stat["size"];
            // md5 = crypto.createHash('md5').update(fs.readFileSync(subpath, 'binary')).digest('hex');
            md5 = crypto.createHash("md5").update(fs.readFileSync(subpath)).digest("hex");
            compressed = path.extname(subpath).toLowerCase() === ".zip";
            relative = path.relative(src, subpath);
            relative = relative.replace(/\\/g, "/");
            relative = encodeURI(relative);
            obj[relative] = {
                size: size,
                md5: md5
            };
            if (compressed) {
                obj[relative].compressed = true;
            }
        }
    }
}

function getVersionDirectory(mode) {
    var str = "";
    param.forEach(element => {
        if (element.name == mode) {
            str = String(element.version) + "/";
        }
    });
    return str;
}

var mkdirSync = function (path) {
    try {
        fs.mkdirSync(path);
    } catch (e) {
        if (e.code != "EEXIST") throw e;
    }
};

var getVersion = function (d) {
    return {
        packageUrl: d.packageUrl,
        remoteManifestUrl: d.remoteManifestUrl,
        remoteVersionUrl: d.remoteVersionUrl,
        version: d.version,
        module: d.module
    };
};

var getProject = function (d) {
    return {
        packageUrl: d.packageUrl,
        remoteManifestUrl: d.remoteManifestUrl,
        remoteVersionUrl: d.remoteVersionUrl,
        version: d.version,
        assets: {},
        searchPaths: [],
        module: d.module
    };
};

// Iterate res and src folder
readDir(path.join(src, "src"), manifest.assets);
readDir(path.join(src, "res"), manifest.assets);

var destManifest = path.join(src, "project.manifest");
var destVersion = path.join(src, "version.manifest");

mkdirSync(dest);

fs.writeFile(destManifest, JSON.stringify(manifest), err => {
    if (err) throw err;
});

fs.writeFile(destVersion, JSON.stringify(getVersion(manifest)), err => {
    if (err) throw err;
});

if (param) {
    function mkdirsSync(dirname) {
        if (fs.existsSync(dirname)) {
            return true;
        } else {
            if (mkdirsSync(path.dirname(dirname))) {
                fs.mkdirSync(dirname);
                return true;
            }
        }
    }
    var copyFile = function (file, mode, houzui) {
        let full = path.join(src, file);
        let dir = file.substring(0, file.lastIndexOf("/"));
        if (mode == "hall") {
            mkdirsSync(
                "./hotupdatatemp/" + qudao + mode + (houzui || "") + "/" + getVersionDirectory(mode) + dir
            );
            fs.writeFileSync(
                path.join(
                    "./hotupdatatemp/" + qudao + mode + (houzui || "") + "/" + getVersionDirectory(mode),
                    file
                ),
                fs.readFileSync(full)
            );
        } else {
            mkdirsSync(
                "./hotupdatatemp/" + qudao + mode + "/" + getVersionDirectory(mode) + dir
            );
            fs.writeFileSync(
                path.join(
                    "./hotupdatatemp/" + qudao + mode + "/" + getVersionDirectory(mode),
                    file
                ),
                fs.readFileSync(full)
            );
        }
    };

    let temp_miss = [];
    let pack = fs.readFileSync(src + "asset_module.json", "utf-8");
    pack = JSON.parse(pack);
    // console.log(pack)
    for (let i = 0; i < param.length; i++) {
        let mod = param[i].name;
        if (mod == "hall") {
            //这里不执行hall
            continue;
        }
        let version = param[i].version;
        let include = param[i].include;

        url = hoturl + mod;
        let project = getProject(manifest);
        project.version = version;
        project.packageUrl = url + "/" + getVersionDirectory(mod);
        project.remoteManifestUrl = url + "/" + mod + "_project.manifest";
        project.remoteVersionUrl = url + "/" + mod + "_version.manifest";
        project.module = mod;

        //根据asset_module记录，分别找出不同模块的资源
        let assets = manifest.assets;
        for (k in assets) {
            let key = k.substring(k.lastIndexOf("/") + 1, k.indexOf(".")); //uuid
            let value = assets[k]; //这是manifest文件内容
            let sname = k.substring(k.lastIndexOf("."));
            if (!pack[key]) {
                if (sname == ".jsc" || sname == ".js") {
                    //字游戏不拷贝js文件 
                    continue;
                }
                key = k.substring(0, k.lastIndexOf("/")); //res/raw-assets/xx/uuid/raw-sket.json
                key = key.substring(key.lastIndexOf("/") + 1);
                if (!pack[key]) {
                    temp_miss.push(k + " key:" + key);
                    continue;
                }
            }
            if (sname == ".json") {
                continue; //字游戏不要json
            }
            if (pack[key].includes(mod) && !pack[key].includes("hall")) {
                if (include) copyFile(k, project.module); //只拷贝文件  不拷贝manifest
            }
        }
        //文件保存生成的version文件  先写到assets目录下
        var pathstr = __dirname + "/hotupdatatemp/" + qudao + project.module + "/" + getVersionDirectory(mod); //文件的绝对路径 当前当前js所在的绝对路径
        var zip_endCallback = () => {
            //遍历上面拷贝完成后的文件夹， import重新打包成zip并且重新生成project_manifest
            var str = __dirname + "/hotupdatatemp/" + qudao + project.module + "/" + getVersionDirectory(mod)
            readDir(path.join(str, "res"), project.assets, true);
            var replaceStr = "../../hotupdatatemp/" + qudao + project.module + "/" + getVersionDirectory(mod)
            var reg = new RegExp(replaceStr, "g");
            //从aseets目录拷贝到字游戏对应目录中
            if (include) {
                //console.log("拷贝manifest文件", "./hotupdatatemp/" + qudao + project.module)
                mkdirsSync("./hotupdatatemp/" + qudao + project.module);
                fs.writeFileSync(
                    "./hotupdatatemp/" +
                    qudao +
                    project.module +
                    "/" +
                    mod +
                    "_project.manifest",
                    JSON.stringify(project).replace(reg, "")
                );
                fs.writeFileSync(
                    "./hotupdatatemp/" +
                    qudao +
                    project.module +
                    "/" +
                    mod +
                    "_version.manifest",
                    JSON.stringify(getVersion(project))
                );
            }
        }
        zip_endCallback();
        //startZIP(pathstr, zip_endCallback)
    }
    //处理大厅的更新脚本
    for (let i = 0; i < param.length; i++) {
        let mod = param[i].name;
        if (mod != "hall") {
            //这里不执行hall
            continue;
        }
        let version = param[i].version;
        let include = param[i].include;
        url = hoturl + mod;
        let project = getProject(manifest);
        project.version = version;
        project.packageUrl = url + "/" + getVersionDirectory(mod);
        project.remoteManifestUrl = url + "/" + "project.manifest";
        project.remoteVersionUrl = url + "/" + "version.manifest";
        project.module = mod;

        let assets = manifest.assets;
        for (k in assets) {
            let key = k.substring(k.lastIndexOf("/") + 1, k.indexOf(".")); //uuid
            let value = assets[k];
            let sname = k.substring(k.lastIndexOf("."));
            if (!pack[key] || sname == ".json") {
                //let sname = k.substring(k.lastIndexOf("."));
                if (sname == ".jsc" || sname == ".js" || sname == ".json") {
                    project.assets[k] = value;
                    if (include) {
                        //copyFile(k, project.module, "_install");
                        copyFile(k, project.module);
                    }
                    continue;
                }
                key = k.substring(0, k.lastIndexOf("/")); //res/raw-assets/xx/uuid/raw-sket.json
                key = key.substring(key.lastIndexOf("/") + 1);
                if (!pack[key]) {
                    temp_miss.push(k + " key:" + key);
                    continue;
                }
            }

            if (pack[key].includes(mod)) {
                project.assets[k] = value;
                if (include) {
                    //copyFile(k, project.module, "_install");
                    copyFile(k, project.module);
                }
            }
        }
        if (include) {

            mkdirsSync("./hotupdatatemp/" + qudao + "hall");
            fs.writeFileSync(
                "./hotupdatatemp/" + qudao + "hall" + "/project.manifest",
                JSON.stringify(project)
            );
            fs.writeFileSync(
                "./hotupdatatemp/" + qudao + "hall" + "/version.manifest",
                JSON.stringify(getVersion(project))
            );

            // mkdirsSync("./hotupdatatemp/" + qudao + "hall_install");
            // fs.writeFileSync(
            //     "./hotupdatatemp/" + qudao + "hall_install" + "/project.manifest",
            //     JSON.stringify(project)
            // );
            // fs.writeFileSync(
            //     "./hotupdatatemp/" + qudao + "hall_install" + "/version.manifest",
            //     JSON.stringify(getVersion(project))
            // );
        }

        var pathstr = __dirname + "/hotupdatatemp/" + qudao + project.module + "/" + getVersionDirectory(mod); //文件的绝对路径 当前当前js所在的绝对路径

        var zip_endCallback = () => {
            //遍历上面拷贝完成后的文件夹， import重新打包成zip并且重新生成project_manifest
            var str = __dirname + "/hotupdatatemp/" + qudao + project.module + "/" + getVersionDirectory(mod)
            readDir(path.join(str, "res"), project.assets, true);
            readDir(path.join(str, "src"), project.assets, true);
            var replaceStr = "../../hotupdatatemp/" + qudao + project.module + "/" + getVersionDirectory(mod)
            var reg = new RegExp(replaceStr, "g");
            if (include) {
                mkdirsSync("./hotupdatatemp/" + qudao + "hall");
                fs.writeFileSync(
                    "./hotupdatatemp/" + qudao + "hall" + "/project.manifest",
                    JSON.stringify(project).replace(reg, "")
                );
                fs.writeFileSync(
                    "./hotupdatatemp/" + qudao + "hall" + "/version.manifest",
                    JSON.stringify(getVersion(project))
                );
            }
        }
        //大厅zip先不做
        //startZIP(pathstr, zip_endCallback)
    }

    if (temp_miss.length > 0) {
        console.log(
            "================================================\n miss mod file\n",
            JSON.stringify(temp_miss)
        );
    }
}